package org.ucas.faker.web.service.heatmap;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.ucas.faker.web.dao.PatentMapper;
import org.ucas.faker.web.service.graph.AdvancedStatService;
import org.ucas.faker.web.service.graph.SpecialKeywordService;
import org.ucas.faker.web.service.graph.TreeTermService;
import org.ucas.faker.web.service.Visualization.SpecialGraphService;
import org.ucas.faker.web.utils.model.Heatmap;
import org.ucas.faker.web.utils.model.TreeTerm;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.*;

@Service
@Transactional
public class HeatmapByTreeService extends AdvancedStatService {

    @Autowired private PatentMapper patentMapper;
    @Autowired private TreeTermService treeTermService;
    @Autowired private SpecialKeywordService specialKeywordService;
    @Autowired private SpecialGraphService specialGraphService;

    private boolean draw[];
    private double topicMatrix[][];

    public Heatmap getHeatmap(long depotId, long treeId) throws IOException {
//        List<HashMap<String, Object>> list = patentMapper.selectPatentGroupByFlowNumber(depotId);
        List<HashMap<String, Object>> list = specialGraphService.getPatentInfo(depotId);
        System.out.println("patent list size="+list.size());

        TreeTerm rootTerm = treeTermService.getTreeTerm(treeId);

        int clusterNum = rootTerm.getChildrenNum();
        Map<String, Double>[] topicMap = new HashMap[clusterNum]; //LdaUtil.translate(phi, corpus.getVocabulary(), 20);

        Comparator<Map.Entry<String, Double>> valueComparator = new Comparator<Map.Entry<String,Double>>() {
            @Override
            public int compare(Map.Entry<String, Double> o1, Map.Entry<String, Double> o2) {
                double diff = o1.getValue()-o2.getValue();
                if (diff > 0) return 1;
                else if (diff < 0) return -1;
                else return 0;
            }
        };

        for (int i=0;i<clusterNum;i++){
            TreeTerm subTerm = rootTerm.getChildTermList().get(i);
            //计算每个subTerm的权重并排序
            Map<String, Double> tmpMap = new HashMap<String, Double>();

            Map<String, Double> tmpWordMap = new HashMap<String, Double>();
            for (int j=0;j<subTerm.getChildrenNum();j++){
                String word = subTerm.getChildTermList().get(j).getWord_CN();
                tmpWordMap.put(word, 0.0);
            }

            for (int j=0;j<subTerm.getChildrenNum();j++){
                String word = subTerm.getChildTermList().get(j).getWord_CN();
                double weight = 0.0;
                for (HashMap<String, Object> patentMap : list){
                    if (patentMap.get("ap_year") == null)  continue;
                    weight += getWeight(word, tmpWordMap, patentMap);
                }
                tmpMap.put(word, weight);
            }

            List<Map.Entry<String, Double>> tmpList = new ArrayList<Map.Entry<String,Double>>(tmpMap.entrySet());
            Map<String, Double> wordMap = new HashMap<String, Double>();
            for (Map.Entry<String, Double> entry : tmpList){
                wordMap.put(entry.getKey(), entry.getValue());
            }
            topicMap[i] = wordMap;
        }

//        topicMap = regularTopicMap(topicMap);

        //计算年份min和max
        int minYear = 9999;
        int maxYear = 0;
        for (HashMap<String, Object> map : list){
            if (map.get("ap_year") != null) {
                int year = Integer.parseInt(map.get("ap_year").toString());
                if (year > maxYear) maxYear = year;
                if (year < minYear) minYear = year;
            }
        }

//        System.out.println("maxYear="+maxYear+"  minYear="+minYear);
//        System.out.println("clusternum="+clusterNum);
        topicMatrix = new double[clusterNum][maxYear-minYear+1];

        System.out.println("topicMatrix: "+clusterNum+"×"+(maxYear-minYear+1));

        for (int i=0;i<clusterNum;i++)
            for (int j=0;j<maxYear-minYear+1;j++)
                topicMatrix[i][j] = 0.0;

        for (int i=0;i<clusterNum;i++){
            Map<String, Double> map = topicMap[i];
            for (HashMap<String, Object> patentMap : list){
                if (patentMap.get("ap_year") == null)  continue;
                int j = Integer.parseInt(patentMap.get("ap_year").toString())-minYear;

                for (String word : map.keySet()) {
//                    System.out.println("compute word="+word);
                    if (getWeight(word, map, patentMap)>3.0){
                        topicMatrix[i][j] += 1.0;
                        break;
                    }
                }
            }
        }

        for (int i=0;i<clusterNum;i++) {
            for (int j = 0; j < maxYear - minYear + 1; j++) {
                System.out.print(topicMatrix[i][j]+"  ");
            }
            System.out.println();
        }


        draw = new boolean[maxYear - minYear + 1];
        draw[0] = true;
        draw[maxYear - minYear] = true;
        boolean firstFlag = true;
        for (int j = 0; j < maxYear - minYear; j++) {
            int count = 0;
            for (int i=0;i<clusterNum;i++) {
                if (topicMatrix[i][j]>0.00001){
                    count ++;
                }
            }
            if (count<=clusterNum/3){
                draw[j] = false;
            }
            else draw[j] = true;

            if (firstFlag == true && count>0){
                draw[j] = true;
                firstFlag = false;
            }
        }

/*        for (int i=0;i<draw.length;i++){
            System.out.print(draw[i]+"  ");
        }
        System.out.println();*/

        //统计
        for (int j = 0; j < maxYear - minYear + 1; j++) {
            double sum = 0.0;
            for (int i=0;i<clusterNum;i++) {
                sum += topicMatrix[i][j];
            }

            if (sum <0.00001){
                sum = 1.0;
            }

            for (int i=0;i<clusterNum;i++) {
                topicMatrix[i][j] = topicMatrix[i][j] / sum;
            }

            for (int i=1;i<clusterNum;i++){
                //topicMatrix[i][j] = topicMatrix[i][j] + topicMatrix[i-1][j];
            }
        }

        for (int i=0;i<clusterNum;i++) {
            for (int j = 0; j < maxYear - minYear + 1; j++) {
                System.out.print(topicMatrix[i][j]+"  ");
            }
            System.out.println();
        }

        Heatmap heatmap = new Heatmap();
        List<String> xList = new ArrayList<String>();
        for (int i=0;i<draw.length;i++){
            if (draw[i] == true){
                xList.add(""+(minYear+i));
            }
        }
        heatmap.setXLabel(xList);

        DecimalFormat df = new DecimalFormat("0.00");

        for (int i=0;i<clusterNum;i++) {
            List<String> lineList = new ArrayList<String>();
            for (int j = 0; j < maxYear - minYear + 1; j++) {
                if (draw[j] == true){
                    lineList.add(""+df.format(topicMatrix[i][j]));
                }
            }
            heatmap.setLine(lineList, i+1);
        }

        List<String> graphList = new ArrayList<String>();
        for (TreeTerm term : rootTerm.getChildTermList()){
            graphList.add(term.getWord_CN());
        }
        heatmap.setGraphLable(graphList);


        //计算每个词的坐标位置
        for (int j = 0; j < maxYear - minYear + 1; j++) {
            for (int i=1;i<clusterNum;i++){
                topicMatrix[i][j] = topicMatrix[i][j] + topicMatrix[i-1][j];
            }
        }

        int enu = 0;

        List<Double> totalXList = new ArrayList<Double>();
        List<Double> totalYList = new ArrayList<Double>();
        List<String> totalWordList = new ArrayList<String>();

        List<List<String>> patentsFromSeries = new ArrayList<List<String>>();

        for (int t=0; t<topicMap.length; t++){
            List<String> patentSeriesList = new ArrayList<String>();
            enu++;
            //注释system。out
            System.out.println("topic:"+enu);

            List<Double> tmpXList = new ArrayList<Double>();
            List<Double> tmpYList = new ArrayList<Double>();
            List<Integer> tmpPositionList = new ArrayList<Integer>();
            List<String> tmpWordList = new ArrayList<String>();

            Map<String, Double> wordMap = topicMap[t];
            for (String word : wordMap.keySet()){
                List<String> patentList = new ArrayList<String>();
                Map<Integer, Integer> counter = new HashMap<Integer, Integer>();
                int totalNum = 0;
                for (HashMap<String, Object> patentMap : list){
                    if (patentMap.get("ap_year") == null)  continue;
                    int j = Integer.parseInt(patentMap.get("ap_year").toString()) - minYear;
                    double kkMax = j;
                    for (int kk = 0; kk<kkMax; kk++){
                        if (draw[kk] == false){
                            j = j - 1;
                        }
                    }

                    if (getWeight(word, wordMap, patentMap)>3.0){
                        totalNum ++;
                        if (counter.containsKey(j)){
                            counter.put(j, counter.get(j)+1);
                        } else {
                            counter.put(j, 1);
                        }
                        if (!patentList.contains(patentMap.get("id").toString())) {
                            patentList.add(patentMap.get("id").toString());
                        }
                        if (!patentSeriesList.contains(patentMap.get("id").toString())){
                            patentSeriesList.add(patentMap.get("id").toString());
                        }
                    }
                }

                if (counter.keySet().size()==0) continue;

                double cx = 0.0;
                double divisor = 0.0;
                double positionWeight = 150.0;
                double positionDivisor = 1.5;
                for (int year : counter.keySet()){
                	//注释system。out
                    System.out.println(year+"  ->  "+counter.get(year));
                    /*double weight = Math.pow(counter.get(year), 2)*positionWeight;
                    positionWeight = positionWeight / positionDivisor;*/
                    double weight = Math.pow(counter.get(year), 2);

                    cx += year * weight + 0.0;
                    divisor += weight + 0.0;
                }
                cx = Math.max(0.01, cx / (divisor + 0.0) - 0.01);  //chenli


                System.out.println("原横坐标="+cx);


                /*//横轴拉伸变换
                double xMax = heatmap.getXMax();
                cx = Math.pow(cx / xMax, 2)*xMax;*/

                //纵轴变换
                double cy = computeY(cx, t, 2);

                //检查位置
                int putResult = 2;
                for (int ww = 0; ww<tmpXList.size(); ww++){
                    double x = tmpXList.get(ww);
                    double y = tmpYList.get(ww);
                    int position = tmpPositionList.get(ww);
                    int newPosition = position;
                    double horizonLength = horizonLength(word, tmpWordList.get(ww));

                    if (Math.abs(x - cx)<=horizonLength/2){
                        putResult = 0;
                        break;
                    } else if (Math.abs(x - cx)>horizonLength/2  &&  Math.abs(x - cx)<=horizonLength){
                        if (position == 1){
                            putResult = 3;
                        } else if (position == 3){
                            putResult = 1;
                        } else if (position == 2){
                            if (y>cy){
                                putResult = 3;
                            } else {
                                putResult = 1;
                            }
                        }
                        break;
                    }
                }

                //同类词条检查
                for (int uu = 0; uu<tmpXList.size(); uu++){
                    double x0 = tmpXList.get(uu);
                    double y0 = tmpYList.get(uu);
                    int position0 = tmpPositionList.get(uu);
                    String tmpWord = tmpWordList.get(uu);
                    double hl = horizonLength(word, tmpWord);
                    if (Math.abs(x0 - cx)<=hl && (putResult == position0 || Math.abs(y0 - cy)<=0.05)){
                        putResult = 0;
                        break;
                    }
                }

                //类间词条检查
                for (int vv = 0; vv<totalXList.size(); vv++){
                    double x0 = totalXList.get(vv);
                    double y0 = totalYList.get(vv);
                    String word0 = totalWordList.get(vv);
                    double hl = horizonLength(word, word0);
                    if (Math.abs(x0 - cx)<=hl && Math.abs(y0 - cy)<=0.05){
                        putResult = 0;
                        break;
                    }
                }

                //边界检测
                if (cx<word.length() / 3.8 || cx>xList.size()- 1 - word.length()/ 3.8){
                    putResult = 0;
                }

                if (putResult != 0){
                    tmpXList.add(cx);
                    cy = computeY(cx, t, putResult);
                    tmpYList.add(cy);
                    tmpPositionList.add(putResult);
                    tmpWordList.add(word);

                    totalXList.add(cx);
                    totalYList.add(cy);
                    totalWordList.add(word);

                    System.out.println("word:"+word+"   position:"+cx+","+cy+"   num="+patentList.size());

                    //可视化坐标变换
                    double coo[] = heatmap.convertWordCoordinate(cx, cy);
                    heatmap.addWord(word, coo[0], coo[1], patentList);
                }
            }
            patentsFromSeries.add(patentSeriesList);
            heatmap.addWord("#", 0, 0, new ArrayList<String>());
        }
        heatmap.setPatentsFromSeries(patentsFromSeries);

        for (int i=0;i<clusterNum;i++) {
            for (int j = 0; j < maxYear - minYear + 1; j++) {
                if (draw[j]==true) {
                    System.out.print(df.format(topicMatrix[i][j]) + "  ");
                }
            }
            System.out.println();
        }

        for (int i=0;i<clusterNum;i++) {
            for (int j = 0; j < maxYear - minYear + 1; j++) {
                System.out.print(df.format(topicMatrix[i][j]) + "  ");
            }
            System.out.println();
        }

        heatmap.printResult();
        return heatmap;
    }

    private double horizonLength(String word1, String word2){
        if (word1 == null) word1 = "";
        if (word2 == null) word2 = "";
        return (word1.length() + word2.length()) / 6.9;
    }

    private double computeY(double cx, int t, int position){
        int a = 0;
        int b = 0;
        for (int zz=0; zz<draw.length; zz++){
            if (draw[zz] == false){
                b = b+1;
            }
            else if (a+1<cx){
                a = a+1;
            } else {
                break;
            }
        }
        a = a+b;
        //注释system。out
        System.out.println("a="+a+",b="+b+", t="+t);

        double pUpper = topicMatrix[t][a];
        double qUpper = topicMatrix[t][a+1];
        double pLower = 0.0;
        double qLower = 0.0;
        if (t != 0){
            pLower = topicMatrix[t-1][a];
            qLower = topicMatrix[t-1][a+1];
        }

        double d = 0.5;
        if (position == 1) d = 0.75;
        else if (position == 2) d = 0.5;
        else if (position == 3) d = 0.25;
        double p = pUpper*d + pLower*(1-d);
        double q = qUpper*d + qLower*(1-d);
        //注释system。out
        //System.out.println("p="+p+", q="+q);
        double cy = (q-p)*(cx-a+b)+p;
        //注释system。out
        return cy;
    }



    private Map<String, Double>[] regularTopicMap(Map<String, Double>[] topicMap){
        //取长词去掉短词
        List<String> wordList = new ArrayList<String>();
        for (Map<String, Double> map : topicMap){
            for (String word : map.keySet()) {
                if (!wordList.contains(word)){
                    wordList.add(word);
                }
            }
        }

        for (Map<String, Double> map : topicMap){
            List<String> removeList = new ArrayList<String>();
            for (String word : map.keySet()) {
                boolean flag = true;
                for (String tmp : wordList){
                    if (tmp.indexOf(word)!=-1 && !tmp.equals(word)){
                        removeList.add(word);
                    }
                }
            }
            for (String removeWord : removeList){
                map.remove(removeWord);
            }
        }

        //取权重大的词
        for (int i=0; i<topicMap.length; i++){
            for (int j=0;j<topicMap.length;j++){
                if (i == j) continue;
                List<String> removeList1 = new ArrayList<String>();
                List<String> removeList2 = new ArrayList<String>();

                Map<String, Double> map1 = topicMap[i];
                Map<String, Double> map2 = topicMap[j];

                for (String word1 : map1.keySet()){
                    for (String word2 : map2.keySet()){
                        if (word1.equals(word2)){
                            if (map1.get(word1)>=map2.get(word2)){
                                removeList2.add(word2);
                            } else {
                                removeList1.add(word1);
                            }
//                            System.out.println("删除相同词："+word1);
                        }
                    }
                }

                for (String word : removeList1){
                    map1.remove(word);
                }
                for (String word : removeList2){
                    map2.remove(word);
                }
            }
        }
        return topicMap;
    }

    private String postSegment(String text){
        String res = "";
        CloseableHttpClient httpclient = HttpClients.createDefault();

        HttpPost httpPost = new HttpPost("http://47.95.255.72:8999/get_segment");
        //httpPost.addHeader("Content-Type","text/html;charset=UTF-8");

        List <NameValuePair> nvps = new ArrayList <NameValuePair>();
        List<NameValuePair> valuePairs = new ArrayList<NameValuePair>(1);
        valuePairs.add(new BasicNameValuePair("sentence", text));

        CloseableHttpResponse response2=null;
        try {
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(valuePairs, "UTF-8");

            httpPost.setEntity(formEntity);
            response2 = httpclient.execute(httpPost);
            //System.out.println(response2.getStatusLine());
            HttpEntity entity2 = response2.getEntity();
            //System.out.println(EntityUtils.toString(entity2,"UTF-8"));
            res = EntityUtils.toString(entity2,"UTF-8");
            // do something useful with the response body
            // and ensure it is fully consumed
            EntityUtils.consume(entity2);
        } catch(Exception e){

        }
        finally {
            //response2.close();
        }
      //注释system。out
        //System.out.println(res);
        return res;
    }



}
